#include "Thread.hpp"
#include "RingQueue.hpp"
#include "Task.hpp"
#include <iostream>
#include <vector>

using namespace ThreadModule;
using std::vector;
using std::cout;
using std::endl;

using ringqueue_t = RingQueue<Task>;

template<typename Func, class... Args>
void CreateThread(vector<Thread*>* v, int num, Func&& func, Args&&... args)
{
    for(int i = 0; i < num; i++)
    {
        v->emplace_back(
            new Thread(
                "thread-" + std::to_string(i + 1), 
                std::forward<Func>(func),
                "thread-" + std::to_string(i + 1),
                std::forward<Args>(args)...));
    }
}

void DeleteThreads(vector<Thread*>& v)
{
    for(auto& e: v)
    {
        delete e;
    }
}

// output mutex: set for keeping print clean
pthread_mutex_t producer_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t consumer_mutex = PTHREAD_MUTEX_INITIALIZER;

void ProducerDone(const std::string& s, ringqueue_t* rq)
{
    while(true)
    {
        pthread_mutex_lock(&producer_mutex);
        cout << "Producer send task ~~~  [" << s << "]" << endl;
        pthread_mutex_unlock(&producer_mutex);

        Task t;
        rq->push(t);
        sleep(1);
        
    }
}
void ConsumerDone(const std::string& s, ringqueue_t& rq)
{
    Task t;
    sleep(5);
    while(true)
    {
        rq.pop(&t);

        pthread_mutex_lock(&consumer_mutex);
        cout << "Consumer get task! ->  [" << s << "]" << endl;
        pthread_mutex_unlock(&consumer_mutex);

        t.doing();
        sleep(2);
    }
}

int main()
{
    ringqueue_t rq;
    vector<Thread*> producer_threads;
    vector<Thread*> consumer_threads;

    CreateThread(&producer_threads, 4, ProducerDone, &rq);
    CreateThread(&consumer_threads, 5, ConsumerDone, std::ref(rq));

    DeleteThreads(producer_threads);
    DeleteThreads(consumer_threads);

    sleep(100);

    return 0;
}
